package android.hermes;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Random;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;


/**
 *  
 * @author Erik, Tobias & Joakim.
 *
 */

//@SuppressWarnings("unused")
public class Hermes extends Activity implements OnClickListener {
	
	public static final String NEW_FRIEND_FOUND = "Found a new friend to talk to! Yay!";
	
	//instance varibles
	WifiManager wifi = null;
	Button sendButton;
	EditText txtBox;
	TextView inbox;
	AdHocWifiManager adhocWifi;
	InetAddress myIP, otherIP;
	ArrayList<InetAddress> friends;
	int myID = 4;
	int someOtherID;
	
    /* (non-Javadoc)
     * @see android.app.Activity#onCreate(android.os.Bundle)
     * Called when the activity is first created.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        //Create the manager for Ad Hoc Wifi
        adhocWifi = new AdHocWifiManager();

        //Initiate the send button
        sendButton = (Button) findViewById(R.id.sendButton);
        sendButton.setOnClickListener(this);
        
        //Initiate the EditText where you write dirty, dirty secrets. 
        txtBox = (EditText) findViewById(R.id.txtBox);
        inbox = (TextView) findViewById(R.id.inbox);
        
        //Disable the usual WiFi
        wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
        wifi.setWifiEnabled(false);
        
        //Create directories and move bin-files.
        createDirs();
        moveFiles();
        
        
        friends = new ArrayList<InetAddress>(3);
        
        
        //Cry Havoc, and engage warp speed...I mean Ad Hoc WiFi.
        adhocWifi.enableWifi();
        
        
        
        //Register receiver to handle some message passing,
        //and start listening for announcements from nearby devices.
        quickRegistering();
        discover();     
        
        
    }
    

	/* (non-Javadoc)
     * @see android.view.View.OnClickListener#onClick(android.view.View)
     */
    public void onClick(View v) {
    	
    	pingOthers();
    	           
    }

    
	
    /**
     * @param message
     * Displays a simple toast 
     */
    public void popMsg(String message) {
    	Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
	}

    public void quickRegistering() {
    	IntentFilter filter;
    	PingReceiver receiver;
    	filter = new IntentFilter(NEW_FRIEND_FOUND);
    	receiver = new PingReceiver();
    	
    	registerReceiver(receiver, filter);
    }
    
    class PingReceiver extends BroadcastReceiver {

		@Override
		public void onReceive(Context c, Intent i) {
		    Bundle b = i.getExtras();
		    otherIP = (InetAddress) b.get("ip");
		    //popMsg(i.getAction());
		    //popMsg(otherIP.toString());
		    
		    //inbox.setText("My IP is " + myIP.toString() + "\nMy friend's IP is " + otherIP);
		    
		    //Kod som ska skriva ut listan med addresser, funkar inte helt perfekt �n.
		    //K�nn er fria att experimentera.
		    /*inbox.setText(inbox.getText() + "\n\nAll known IPs are ");
		    for(int j=0; j< friends.size();j++){
		    	inbox.setText(inbox.getText() + "" + friends.get(j) + "\n");
		    }*/
		}
    	
    }
    
    private void informMain(InetAddress ip) {
		//Create an intent to send and put the IP-address in it
		Intent intent = new Intent(NEW_FRIEND_FOUND);
		intent.putExtra("ip", ip);
		
		//send the intent
		sendBroadcast(intent);    		
	}
    
    private void pingOthers () {
    	Thread ER = new Thread(new Runnable() {
    		public void run() {
		    	try {
		    		
			    	byte[] buf = new byte[1];
					buf[0] = (byte) myID;				
					DatagramSocket sockan = new DatagramSocket();
					InetAddress target;
					DatagramPacket packet;
	
					for(int i=1; i<255;i++) {
						target = InetAddress.getByName("192.168.42." + i);
						packet = new DatagramPacket(buf, buf.length, target, 24242);
						
						sockan.send(packet);
					}
		    	}
		    	catch (Exception e){
		    		
		    	}
    		}
    	});
    	ER.start();
    }
    
    private void discover () {
    	Thread t = new Thread(new Runnable() {
    		public void run() {
    			InetAddress incoming;
    			
    			while(true) {
    				try {
    					//Contents of the packet we send doesn't matter at this point
    					byte[] buf = new byte[1];
    					buf[0] = (byte) 10101010;				
    					DatagramPacket packet = new DatagramPacket(buf, buf.length);

    					DatagramSocket ds = new DatagramSocket(24242);
    					
    					//wait for an incoming message and extract the senders IP-address
    					ds.receive(packet);
    					incoming = packet.getAddress();
    					
    					byte[] data = packet.getData();
    					someOtherID = (int) data[0];
    					
    					//if we dont "know" this ip yet...
    					if(!friends.contains(incoming)) {
    						
    						//...add it to our list of friends!
    						friends.add(incoming);
    						
    						//Acknowledge sender by replying
    						packet = new DatagramPacket(buf, buf.length, incoming, 24242);
    						ds.send(packet);
    						
    						//Pass the friends IP-address on to the main thread
    						informMain(incoming);
    						otherIP = incoming;
    						popMsg("Phone #"+someOtherID+" has IP: "+otherIP);
    					}
    					else {
    						//This ip has already pinged us recently,
    						//so we do nothing. Should probably implement some
    						//form of decay...
    					}
    					
    					
    				} catch (Exception e) {
    					
    					
    				}
    			}
    		}
    	});
    	t.start();
    }
        
    
    
    
    
    /**
     * Create the necessary directories
     */
    private void createDirs() {
    	File dir = new File("/data/data/android.hermes/");
    	if (dir.exists() == false) {
    			Hermes.this.popMsg("Application data-dir does not exist!");
    	}
    	else {
	    	dir = new File("/data/data/android.hermes/bin");
	    	if (dir.exists() == false) {
	    		if (!dir.mkdir()) {
	    			Hermes.this.popMsg("Couldn't create bin-directory!");
	    		}
	    	}
	    	dir = new File("/data/data/android.hermes/conf");
	    	if (dir.exists() == false) {
	    		if (!dir.mkdir()) {
	    			Hermes.this.popMsg("Couldn't create conf-directory!");
	    		}
	    	}
	    	dir = new File("/data/data/android.hermes/Sockets");
	    	if (dir.exists() == false) {
	    		if (!dir.mkdir()) {
	    			Hermes.this.popMsg("Couldn't create Sockets-directory!");
	    		}
	    	}
    	}
    	
    }
    /**
     * Copies the essential files to their places, and makes some executable.
     */
    private void moveFiles() {
    	
    	
    	//wpaX.conf
    	this.copyBinary("/data/data/android.hermes/conf/wpa.conf", R.raw.wpa_conf);
    	this.copyBinary("/data/data/android.hermes/conf/tiwlan.ini", R.raw.tiwlan_ini);

    	/*
    	// wifi
    	this.copyBinary("/data/data/android.hermes/bin/wifi", R.raw.wifi);
    	this.copyBinary("/data/data/android.hermes/bin/connect", R.raw.connect);
    	
    	//Change rights to be able to execute the shell scripts
    	runRootCommand("chmod 777 /data/data/android.hermes/bin/wifi");
    	runRootCommand("chmod 777 /data/data/android.hermes/bin/connect");
    	*/
    }
    /**
     * Creates a file from a resource, "copying" it.
     */
    private void copyBinary(String filename, int resource) {
    	File outFile = new File(filename);
    	InputStream is = this.getResources().openRawResource(resource);
    	byte buf[]=new byte[1024];
        int len;
        try {
        	OutputStream out = new FileOutputStream(outFile);
        	while((len = is.read(buf))>0) {
				out.write(buf,0,len);
			}
        	out.close();
        	is.close();
		} catch (IOException e) {
			Hermes.this.popMsg("Couldn't install file - "+filename+"!");
		}
    }
}